mod rx;
mod tx;

use alloc::boxed::Box;
use async_ach_spsc::heap as spsc;
use futures_util::future::{select, Either};
use nrf_softdevice::ble::Connection;
use rx::{Rx, Server};
use tx::Tx;
use unmp_link::prelude::Bytes;

pub(crate) const LEN: usize = 20;

pub fn init() {
    Server::init();
}

pub struct DataChannel {
    pub tx: spsc::Sender<Bytes, 3>,
    pub rx: spsc::Receiver<Bytes, 3>,
}

pub struct ConnDaemon {
    conn: Connection,
    tx_recver: spsc::Receiver<Bytes, 3>,
    rx_sender: spsc::Sender<Bytes, 3>,
}
impl ConnDaemon {
    pub fn new(conn: Connection) -> (Self, DataChannel) {
        let (tx, tx_recver) = spsc::channel();
        let (rx_sender, rx) = spsc::channel();
        let me = Self {
            conn,
            tx_recver,
            rx_sender,
        };
        (me, DataChannel { tx, rx })
    }
}

#[embassy::task(20)]
pub async fn daemon_conn(conn: ConnDaemon) {
    let mut tx_recver = conn.tx_recver;
    let mut rx_sender = conn.rx_sender;
    let conn = conn.conn;
    let ble_tx = Tx::new(&conn).await.unwrap();
    let mut recv_ble = Box::pin(Rx::recv(conn, |data| {
        if rx_sender.try_send(data).is_err() {
            log::warn!("spsc full");
        }
    }));
    loop {
        let recv_data = Box::pin(tx_recver.recv());
        match select(recv_ble, recv_data).await {
            Either::Left(_) => {
                break;
            }
            Either::Right((data, fut)) => {
                recv_ble = fut;
                let _ = ble_tx.send(&data).await;
            }
        }
    }
}
